// 导入内容类型枚举，规范响应头的 Content-Type 设置
import { ContentType } from '../enums/request.enum'
// 导入 RxJS 操作符和类型，用于处理异步数据流
import { map, Observable } from 'rxjs'
// 导入 Reflector，用于从装饰器中获取元数据（此处预留扩展能力）
import { Reflector } from '@nestjs/core'
// 导入 NestJS 核心模块：执行上下文、拦截器接口、HTTP 状态码等
import { CallHandler, ExecutionContext, HttpStatus, Injectable, Logger, NestInterceptor } from '@nestjs/common'
import { DecoratorEnum } from '..'

/**
 * 响应拦截器：统一 API 响应格式，添加额外响应信息，实现 NestInterceptor 接口，用于对控制器返回的响应进行统一处理
 *  1. 标准化响应结构，包含状态码、成功标识、消息、数据等字段
 *  2. 自动计算请求处理耗时，便于性能监控
 *  3. 统一设置 JSON 响应头，确保客户端正确解析
 */
@Injectable()
export class ResponseInterceptor implements NestInterceptor {
  private logger = new Logger(ResponseInterceptor.name)

  // 注入 Reflector（用于后续可能的元数据读取，如自定义响应消息）
  constructor(private readonly reflector: Reflector) {}

  /**
   * 拦截器核心方法：处理请求响应流程
   * @param context 执行上下文：包含当前请求的所有信息（请求对象、响应对象等）
   * @param next 调用处理器：用于将请求传递给下一个拦截器或控制器
   * @returns 经过处理的响应数据流（Observable）
   */
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    // 从执行上下文切换到 HTTP 上下文，获取 Express 的 Request 对象
    const request = context.switchToHttp().getRequest<ExpressRequest>()
    // 从执行上下文切换到 HTTP 上下文，获取 Express 的 Response 对象
    const response = context.switchToHttp().getResponse<ExpressResponse>()
    // 记录请求开始时间，用于计算响应耗时
    const startTime = Date.now()

    // 判断是否允许返回原生响应数据
    const allowNoTransform = this.reflector.getAllAndOverride<boolean>(DecoratorEnum.RAW_METADATA, [context.getHandler(), context.getClass()])

    const { method, query, body, path } = request

    // 处理控制器返回的数据流（next.handle() 会触发后续处理链）
    return next.handle().pipe(
      map((data) => {
        // 返回原生数据
        if (allowNoTransform) return data

        const record = this._buildResponseData(data, startTime)
        this.logger.log(JSON.stringify({ message: '请求成功', method, path, duration: record.duration, query, body }))
        // 设置响应内容类型为 JSON 格式（使用枚举确保准确性）
        response.setHeader('Content-Type', ContentType.APPLICATION_JSON)
        // 直接返回处理后的响应数据，由框架发送响应
        return record
      }),
    )
  }

  /**
   * 构建标准化响应数据结构
   * 使用 Reflect.set 而非直接赋值，为后续可能的元数据驱动配置预留扩展点
   * @param data 控制器返回的原始业务数据
   * @param startTime 请求处理开始时间戳
   * @returns 标准化的响应对象
   *
   * 响应结构说明：
   * - code: HTTP 状态码（200 表示成功）
   * - success: 布尔值标识请求是否成功
   * - message: 响应提示消息（可通过元数据动态修改）
   * - data: 实际业务数据（控制器返回的原始数据）
   * - duration: 处理耗时（毫秒），用于性能分析
   * - timestamp: 响应时间戳，便于问题追踪
   */
  private _buildResponseData(data: any, startTime: number) {
    const result: Recordable = {}
    const endTime = Date.now()
    Reflect.set(result, 'code', HttpStatus.OK)
    Reflect.set(result, 'success', true)
    Reflect.set(result, 'message', '请求成功')
    Reflect.set(result, 'data', data)
    Reflect.set(result, 'duration', endTime - startTime)
    Reflect.set(result, 'timestamp', endTime)
    // Reflect.set(result, 'timestamp', dayjs(endTime).format(TimeFormat.DATETIME_DASH))
    return result
  }
}
